/*
 * Created on Mar 26, 2006
 *
 */
package org.mushroomdb.storedprocedures;

import java.util.StringTokenizer;

import org.mushroomdb.parser.Parser;
import org.mushroomdb.parser.ParserException;
import org.mushroomdb.query.Query;

/**
 * CREATE PROCEDURE procedure_name (options) AS LANGUAGE JAVA (<java-code>);
 * 
 * EXECUTE PROCEDURE procedure_name (parameters);
 * 
 * DROP PROCEDURE procedure_name;
 * 
 * @author Matu
 */
public class StoredProceduresParser implements Parser {

	/**
	 * Constructs a new StoredProceduresParser.
	 */
	public StoredProceduresParser() {
	}

	/**
	 * @see org.mushroomdb.parser.Parser#parseQuery(java.lang.String)
	 */
	public Query parseQuery(String query) throws ParserException {
		
		try {
			if (query.indexOf("CREATE PROCEDURE") > -1 || query.indexOf("create procedure") > -1) {
				return this.parseCreate(query);
			} else if (query.indexOf("EXECUTE PROCEDURE") > -1 || query.indexOf("execute procedure") > -1) {
				return this.parseExecute(query);
			} else {
				return this.parseDrop(query);
			}
		} catch (Exception e) {
			if (e instanceof ParserException) {
				throw (ParserException) e;
			} else {
				throw new ParserException(e);
			}
		}
	}
	
	/**
	 * 
	 * @param query
	 * @return
	 * @throws ParserException
	 */
	private Query parseCreate(String query) throws ParserException {
		String procedureName;
		String code;
		String codeString = query;
		
		StringTokenizer tokenizer = new StringTokenizer(query);
		
		/* CREATE PROCEDURE */
		String token = tokenizer.nextToken();
		if ("CREATE".equals(token)) {
			codeString = codeString.replaceFirst("CREATE","");
		} else if ("create".equals(token)) {
			codeString = codeString.replaceFirst("create","");
		} else {
			throw new ParserException("CREATE expected.");
		}
		token = tokenizer.nextToken();
		if ("PROCEDURE".equals(token)) {
			codeString = codeString.replaceFirst("PROCEDURE","");
		} else if ("procedure".equals(token)) {
			codeString = codeString.replaceFirst("procedure","");
		} else {
			throw new ParserException("PROCEDURE expected.");
		}
		
		/* Procedure's name */
		procedureName = tokenizer.nextToken();
		codeString = codeString.trim();
		codeString = codeString.substring(codeString.indexOf(' '),codeString.length());

		/* AS LANGUAGE JAVA */
		token = tokenizer.nextToken();
		if ("AS".equals(token)) {
			codeString = codeString.replaceFirst("AS","");
		} else if ("as".equals(token)) {
			codeString = codeString.replaceFirst("as","");
		} else {
			throw new ParserException("AS expected.");
		}
		token = tokenizer.nextToken();
		if ("LANGUAGE".equals(token)) {
			codeString = codeString.replaceFirst("LANGUAGE","");
		} else if ("language".equals(token)) {
			codeString = codeString.replaceFirst("language","");
		} else {
			throw new ParserException("LANGUAGE expected.");
		}
		token = tokenizer.nextToken();
		if ("JAVA".equals(token)) {
			codeString = codeString.replaceFirst("JAVA","");
		} else if ("java".equals(token)) {
			codeString = codeString.replaceFirst("java","");
		} else {
			throw new ParserException("JAVA expected.");
		}
		
		/* Code */
		codeString = codeString.trim();
		if (codeString.startsWith("(")) {
			codeString = codeString.substring(1).trim();
		} else {
			throw new ParserException("'(' expected.");
		}
		if (codeString.endsWith(";")) {
			codeString = codeString.substring(0,codeString.length() - 1).trim();
		}
		codeString = codeString.trim();
		if (codeString.endsWith(")")) {
			codeString = codeString.substring(0,codeString.length() - 1).trim();
		} else {
			throw new ParserException("')' expected.");
		}
		code = codeString.trim();
		// FIXME!!!!! El cliente corta por los ";"
		code = code.replaceAll(":",";");
		
		return new CreateProcedureQuery(procedureName,null,code);
	}

	/**
	 * 
	 * @param query
	 * @return
	 * @throws ParserException
	 */
	private Query parseExecute(String query) throws ParserException {
		String procedureName;
		
		StringTokenizer tokenizer = new StringTokenizer(query);
		
		/* EXECUTE PROCEDURE */
		String token = tokenizer.nextToken();
		if (!"EXECUTE".equals(token) && !"execute".equals(token)) {
			throw new ParserException("EXECUTE expected.");
		}
		token = tokenizer.nextToken();
		if (!"PROCEDURE".equals(token) && !"procedure".equals(token)) {
			throw new ParserException("PROCEDURE expected.");
		}
		
		/* Procedure's name */
		procedureName = tokenizer.nextToken();
		if (procedureName.endsWith(";")) {
			procedureName = procedureName.substring(0,procedureName.length() - 1);
		}
		
		return new ExecuteProcedureQuery(procedureName);
	}
	
	/**
	 * 
	 * @param query
	 * @return
	 * @throws ParserException
	 */
	private Query parseDrop(String query) throws ParserException {
		String procedureName;
		
		StringTokenizer tokenizer = new StringTokenizer(query);
		
		/* DROP PROCEDURE */
		String token = tokenizer.nextToken();
		if (!"DROP".equals(token) && !"drop".equals(token)) {
			throw new ParserException("DROP expected.");
		}
		token = tokenizer.nextToken();
		if (!"PROCEDURE".equals(token) && !"procedure".equals(token)) {
			throw new ParserException("PROCEDURE expected.");
		}
		
		/* Procedure's name */
		procedureName = tokenizer.nextToken();
		if (procedureName.endsWith(";")) {
			procedureName = procedureName.substring(0,procedureName.length() - 1);
		}
		
		return new DropProcedureQuery(procedureName);
	}
	
	/**
	 * @see org.mushroomdb.parser.Parser#accepts(java.lang.String)
	 */
	public boolean accepts(String query) {
		return query.toUpperCase().indexOf("CREATE PROCEDURE") > -1
		||
		query.toUpperCase().indexOf("DROP PROCEDURE") > -1
		||
		query.toUpperCase().indexOf("EXECUTE PROCEDURE") > -1;
	}

}
